#include "log.hpp"
#include <condition_variable>
#include<vector>
#include<thread>
#include<queue>


template <typename T>
class ThreadPool
{
public:
    static ThreadPool<T>*  GetTP()
    {
        if(_p == nullptr)
        {
            std::lock_guard<std::mutex> lg(_lock);
            if(_p == nullptr)
            {
                _p = new ThreadPool<T>;
            }
        }
        LOG(LogLevel::INFO) << "获取线程池单例";
        return _p;
    }


    void Push(const T& data)
    {   
        std::lock_guard<std::mutex> lg(_mutex);
        _q.push(data);
        int size = _q.size();
        int work =  _num-_sleepnum;
        int num = _num;
        while(size  > work &&  work < num)
        {
            _cv.notify_one();
            LOG(LogLevel::INFO) << "通知一个线程";
            ++work;
        }
    }

    void Stop()
    {
        std::lock_guard<std::mutex> lg(_mutex);
        _isrunning = false;
        if(_sleepnum)
        {
            LOG(LogLevel::INFO) << "通知所有线程";
            _cv.notify_all();
        }
        LOG(LogLevel::INFO) << "线程池stop";
    }

    void HandleTask()
    {
        while(true)
        {
            T t;
            {
                std::unique_lock<std::mutex> ul(_mutex);
                while(_q.empty() && _isrunning)
                {
                    ++_sleepnum;
                    _cv.wait(ul);
                    --_sleepnum;
                }
                if(_q.empty() && !_isrunning)
                {
                    break;
                }
                t = _q.front();
                _q.pop();
            }
            t();
        }
    }

    void Join()
    {
        for(auto& e : _v)
        {
            e.join();
        }
    }

private:
    ThreadPool(int num = 5)
    :_num(num)
    ,_isrunning(true)
    ,_sleepnum(0)
    {
        for(int i = 0;i < _num;++i)
        {
            _v.emplace_back([this]()
            {  
                HandleTask();
            });       
            LOG(LogLevel::INFO) << "线程成功创建";
        }
    }

    ThreadPool(const ThreadPool<T>&) = delete;
    ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;

    std::vector<std::thread> _v;
    int _num;
    std::queue<T> _q;
    std::condition_variable _cv;
    std::mutex _mutex;
    bool _isrunning;
    int _sleepnum;
    static ThreadPool<T>* _p;
    static std::mutex _lock;
};

template <typename T>
ThreadPool<T>* ThreadPool<T>::_p = nullptr;

template <typename T>
std::mutex ThreadPool<T>::_lock;
